package PenTest.zhiyukeji;

import java.util.LinkedList;
import java.util.Queue;

//基于以下代码完成工具类BoundedBlockingQueue，能支持多线程的同时写入，和阻塞取数，要求尽可能地高效
class BoundedBlockingQueue<T>{
    //limit: 队列最大长度，如果在达到最大长度时插入元素，则阻塞在push函数中，直到队列中有空位为止。
    private int limit;
    private Queue<T> queue;
    //waitMs: 队列为空时最长等待时长，单位ms
    private int waitMs;
    public BoundedBlockingQueue(int limit, int waitMs){
        this.limit = limit;
        this.waitMs = waitMs;
        this.queue = new LinkedList<>();
    }
    //插入元素到队列尾部
    public synchronized void push(T obj){
        while(queue.size() == limit){
            try {
                wait();
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        if(queue.size() == 0){
            notifyAll();
        }
        queue.add(obj);
    }
    //从队列头部取出元素，如果没有元素等待timeoutMs后弹出null
    public synchronized T pop() throws InterruptedException {
        while(queue.size() == 0){
            try {
                wait(waitMs);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
        if(queue.size() == limit){
            notifyAll();
        }
        return queue.remove();
    }
}
//编写一段范例代码，实现十个线程同时插入20个元素，另一个线程取数并打印200个元素。
class Thread1 implements Runnable{
    private int[] arrays;
    private BoundedBlockingQueue<Integer> queue;
    public Thread1(int[] arrays, BoundedBlockingQueue<Integer> queue){
        this.arrays = arrays;
        this.queue = queue;
    }

    @Override
    public void run() {
        for(int i=0;i<arrays.length;i++){
            queue.push(arrays[i]);
        }
    }
}
class Thread2 implements Runnable{
    private BoundedBlockingQueue<Integer> queue;
    public Thread2(BoundedBlockingQueue<Integer> queue){
        this.queue = queue;
    }

    @Override
    public void run() {
        for(int i=0;i<200;i++){
            try {
                int x=queue.pop();
                System.out.println(""+x);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

public class test{
    public static void main(String[] args) throws InterruptedException {
        BoundedBlockingQueue queue = new BoundedBlockingQueue<>(300, 60);
        int[] arrays = new int[]{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20};
        for (int i = 0; i < 10; i++) {
            new Thread(new Thread1(arrays,queue)).start();
        }
        new Thread(new Thread2(queue)).start();
    }
}
